#include <stdio.h>
#include <errno.h>

#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <time.h>
static char sp[]= {97}; 
struct bufferevent{
	char *name;
};

struct user_session{
    int fd;
    struct bufferevent *bev;
	struct user_session *next;
};


static int int2IntArray(long k,int *rtn)
{
	if(k<0) k=abs(k);
	if(k>10)
	{
		k=k%100;
		rtn[0]=(int)(1.0*k/10);
		rtn[1]=k%10;
		return 1;
	} 
	
	rtn[0]=0;
	rtn[1]=k;
	return 1; 
}

int randnum(int min, int max){
	return min+rand()%(max-min);
}

struct user_session *get_user(int fd, struct user_session *users[10][10])
{
	int rtn[2]={0,0};
	int2IntArray(fd, rtn);
	struct user_session * head = users[rtn[0]][rtn[1]];
	//printf("0=%d,1=%d\n", rtn[0], rtn[1]);
	
	while(head->bev!=NULL)
	{
		//printf("head->fd=%d\n",head->fd);
		if(head->fd == fd) return head;
		if(head->next==NULL) break;
		head = head->next;
	}
	return NULL;
}

int remove_count = 0;
static void remove_user(int fd, struct user_session *users[10][10])
{
	if(fd<1) return;
	int rtn[2]={0,0};
	int2IntArray(fd, rtn);
	//struct user_session * head = users[rtn[0]][rtn[1]];
	struct user_session ** current = &users[rtn[0]][rtn[1]];
	struct user_session * pre = NULL;
	int i=0;
	while((*current)->bev!=NULL)
	{
		if((*current)->fd == fd){
			free((*current)->bev->name);
			free((*current)->bev);
			
			(*current)->bev = NULL;
			(*current)->fd = 0;

			if((*current)->next!=NULL)
			{
				struct user_session * tmp = *current;
				if(i==0)
					*current = (*current)->next;
				else
					pre->next = (*current)->next;
				free(tmp);
			}
			else
			{
				if(i!=0)
				{
					free(*current);	
				}
				(*current)->next = NULL;
			}
			remove_count++;
			return;
		}
		//printf("%d,%d=> fd=%d,head->fd=%d\n",rtn[0],rtn[1],fd,(*current)->fd);
		if((*current)->next==NULL) break;

		pre = *current;
		current = &((*current)->next);

		i++;
	}
	printf("%d not found!\n",fd);
}
int add_count = 0;
static void add_user(int fd, struct bufferevent *bev,struct user_session *users[10][10]){
	int rtn[2]={0,0};
	int2IntArray(fd, rtn);
	struct user_session *head;
	head= users[rtn[0]][rtn[1]];
	int count=0;

	while( head->next!=NULL )
	{
		count++;
		head = head->next;
	}

	if(head->bev==NULL){
		printf("add first[%d,%d],count=%d\n",rtn[0],rtn[1],count);
		head->bev = bev;
		head->fd = fd;
		head->next = NULL;
	}
	else
	{
		add_count++;
		printf("add new[%d,%d],count=%d\n",rtn[0],rtn[1],count);
		struct user_session *new_user;
		new_user = malloc(sizeof(struct user_session));
		new_user->fd = fd;
		new_user->bev = bev;
		new_user->next = NULL;	
		head->next = new_user;
	}
}

void fall(struct user_session *users[10][10])
{
	int i,j;
	struct user_session * head;
	struct user_session * current;
	int count = 0;
	for(i=0;i<10;i++)
	{
		for(j=0;j<10;j++)
		{
			head = users[i][j];
			count = 0;
			while(1)
			{
				count++;
				
				if(head->bev==NULL){
					free(head);
					remove_count++;
					if(head->next==NULL)
						break;
					else
						printf("=============>%d,%d=>bev is null , next is not null\n",i,j);
				}else{
					free(head->bev->name);
					free(head->bev);
				}
				if(head->next==NULL){
					remove_count++;
					free(head);
					break;
				}
				current = head;
				head = head->next;
				free(current);
				remove_count++;
			}
			printf("%d,%d=> %d\n",i,j,count);
		}
		printf("\n");
	}
}

static double microtime()
{
	struct timeval tv;
	double t;
	gettimeofday(&tv, NULL);
	t=tv.tv_sec+(double)tv.tv_usec/1000;
	return t;
}


void many_test(int more_user)
{
	struct user_session *users[10][10];
		int i=0;
	int j=0;
	srand(time(0));

	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
		{
			users[i][j] = malloc(sizeof(struct user_session));
			users[i][j]->fd = 0;
			users[i][j]->next = NULL;
			users[i][j]->bev = NULL;
		}
	

	more_user+=5000;
	for(i=1;i<more_user;i++)
	{
		struct bufferevent *bev=malloc(sizeof(struct bufferevent));
		char *name = malloc(100);
		sprintf(name, "lein_%d", i);
		bev->name = name;
		//printf("i=%d\n", i);
		add_user(i, bev, users);
	}
	printf("add user done\n");
	sleep(2);
	double t1;
	int count = 5000;
	t1= microtime();
	while(--count>0)
	{		
		int fd = randnum(1,4999+more_user);
		//printf("rd=%d\n", fd);
		struct user_session *user;
		user = get_user(fd, users);
		if(user==NULL) continue;
		printf("fd=%d, name=%s\n", fd, user->bev->name);

		int fd1 = randnum(1,4999+more_user);
		remove_user(fd1, users);
		
		//usleep(500000);
	}
	printf("\n==================\ntotal use %20.12f\n", microtime()-t1	);
	fall(users);
	printf("sizeof(struct user_session)= %d\nremove_count=%d,add_count=%d\n,left = %d\n", 
		sizeof(struct user_session),remove_count,add_count, add_count +100 -remove_count);
	
}
void add_and_remove_test()
{
	struct user_session *users[10][10];
	int i=0;
	int j=0;
	srand(time(0));

	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
		{
			users[i][j] = malloc(sizeof(struct user_session));
			users[i][j]->fd = 0;
			users[i][j]->next = NULL;
			users[i][j]->bev = NULL;

			//printf("&users[i][j]=%ld\n",users[i][j]);
		}
	for(i=1;i<1000;i+=100)
	{
		struct bufferevent *bev=malloc(sizeof(struct bufferevent));
		char *name = malloc(100);
		sprintf(name, "lein_%d", i);
		bev->name = name;
		//printf("i=%d\n", i);
		add_user(i, bev, users);
	}

	remove_user(1, users);
	
	remove_user(201, users);
	remove_user(301, users);
	remove_user(401, users);
	remove_user(501, users);
	remove_user(601, users);
	remove_user(701, users);
	remove_user(801, users);
	remove_user(901, users);
	struct user_session *user;
	user = get_user(101, users);
	if(user!=NULL)
		printf("101 = %s\n", user->bev->name);
	else
		printf("101 is not found\n");
	remove_user(101, users);

	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
			if( i!=0 || j!=1 )free(users[i][j]);
}


main (int argc, char **argv){
	add_and_remove_test();
	printf("small test done\n");
	sleep(3);
	int more_user = argc>1?atoi(argv[1]):0;	
	many_test(more_user);	
}

